001 /*
002 * Copyright 2005 Niclas Hedhman
003 * Copyright 2005 Stephen J. McConnell.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.
015 *
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 package net.dpml.transit.link;
021
022 import net.dpml.util.StreamUtils;
023
024 import java.io.ByteArrayInputStream;
025 import java.io.ByteArrayOutputStream;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.io.OutputStream;
029 import java.net.URI;
030 import java.net.URL;
031 import java.security.AccessController;
032 import java.security.PrivilegedActionException;
033 import java.security.PrivilegedExceptionAction;
034
035 import net.dpml.transit.Artifact;
036 import net.dpml.transit.NullArgumentException;
037 import net.dpml.transit.artifact.ArtifactNotFoundException;
038 import net.dpml.util.PropertyResolver;
039
040 /**
041 * A link manager that maintains persistent link information as a resource.
042 * Link resource located using the [cache]/[group]/[name]/[type]s/[name]-[version].[type].link
043 * resource naming convention.
044 *
045 * Applications should not call the methods for the LinkManager directly,
046 * and it is likely that the LinkManager remains outside the reachability of
047 * applications.
048 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
049 * @version 1.0.1
050 */
051 public class ArtifactLinkManager
052 implements LinkManager
053 {
054 /**
055 * Sets the URI for the provided Link.
056 * The LinkManager is required to persist this information between
057 * JVM restarts and should be persisted on a scope larger than a
058 * single JVM, typically a host or a local area network. LinkManagers
059 * are encouraged to establish other virtual scopes independent of
060 * network topologies.
061 *
062 * @param linkUri the uri of the link resource
063 * @param targetUri the uri that the link redirects to
064 * @exception IOException if the mapping could not be updated.
065 */
066 public void setTargetURI( final URI linkUri, final URI targetUri )
067 throws IOException
068 {
069 if( null == linkUri )
070 {
071 throw new NullArgumentException( "linkUri" );
072 }
073
074 try
075 {
076 AccessController.doPrivileged(
077 new PrivilegedExceptionAction()
078 {
079 public Object run()
080 throws IOException
081 {
082 String artifact = linkUri.toASCIIString();
083 URL store = new URL( null, artifact, new net.dpml.transit.artifact.Handler() );
084 OutputStream out = store.openConnection().getOutputStream();
085 byte[] array = getByteArray( targetUri );
086 ByteArrayInputStream in = new ByteArrayInputStream( array );
087 StreamUtils.copyStream( in, out, true );
088 return null; // nothing to return
089 }
090 }
091 );
092 }
093 catch( PrivilegedActionException e )
094 {
095 throw (IOException) e.getException();
096 }
097 }
098
099 /**
100 * Returns the URI that the provided link URI instance is pointing to.
101 * @param linkUri the link uri from which the target will be resolved
102 * @exception LinkNotFoundException if the supplied link uri could not be located
103 * @exception IOException if the mapping could not be retrieved, due to
104 * an IOException during link retrival.
105 * @return target URI that the link points to (possibly null if the link does
106 * not declare a target)
107 */
108 public URI getTargetURI( final URI linkUri )
109 throws IOException, LinkNotFoundException
110 {
111 try
112 {
113 URI result = (URI) AccessController.doPrivileged(
114 new PrivilegedExceptionAction()
115 {
116 public Object run()
117 throws IOException
118 {
119 URL store = null;
120 if( Artifact.isRecognized( linkUri ) )
121 {
122 String artifact = linkUri.toASCIIString();
123 store = new URL( null, artifact, new net.dpml.transit.artifact.Handler() );
124 }
125 else
126 {
127 store = linkUri.toURL();
128 }
129
130 ByteArrayOutputStream out = new ByteArrayOutputStream();
131 InputStream in = store.openConnection().getInputStream();
132 StreamUtils.copyStream( in, out, true );
133 String target = out.toString( "ISO8859-1" );
134 String path = PropertyResolver.resolve( target );
135 URI value = URI.create( path );
136 return value;
137 }
138 }
139 );
140 return result;
141 }
142 catch( PrivilegedActionException e )
143 {
144 Exception exception = e.getException();
145 if( exception instanceof ArtifactNotFoundException )
146 {
147 final String error =
148 "Link not found: "
149 + linkUri;
150 throw new LinkNotFoundException( error, linkUri );
151 }
152 else
153 {
154 throw (IOException) exception;
155 }
156 }
157 }
158
159 private byte[] getByteArray( URI uri ) throws IOException
160 {
161 if( null != uri )
162 {
163 return uri.toString().getBytes( "ISO8859-1" );
164 }
165 else
166 {
167 return new byte[0];
168 }
169 }
170 }